package com.skyline.energy.jdbc.impl.queued;

import com.skyline.common.concurrent.queue.TaskParameters;
import com.skyline.common.reflection.ArrayUtils;
import com.skyline.energy.jdbc.impl.PreparedStatementCallback;

/**
 * JDBC查询任务参数集
 * 
 * @author wuqh
 * @see TaskParameters
 */
public class JdbcQueryTaskParameters implements TaskParameters {
	private final String sql;
	private final int fetchSize;
	private final boolean returnKeys;
	private final PreparedStatementCallback<?> action;
	private final Object[] args;
	private final int hashCode;

	public JdbcQueryTaskParameters(String sql, int fetchSize, boolean returnKeys, PreparedStatementCallback<?> action,
			Object... args) {
		int hashCode = 0;

		this.sql = sql;
		hashCode += sql.hashCode();

		this.fetchSize = fetchSize;
		hashCode += fetchSize;

		this.returnKeys = returnKeys;
		hashCode += (returnKeys ? 1231 : 1237);

		this.action = action;

		this.args = args;

		if (args != null) {
			for (Object arg : args) {
				hashCode += (arg == null ? 0 : arg.hashCode());
			}
		}

		this.hashCode = 17 + 23 * hashCode;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj == null) {
			return false;
		}

		if (obj instanceof JdbcQueryTaskParameters == false) {
			return false;
		}

		if (obj == this) {
			return true;
		}

		JdbcQueryTaskParameters parameters = (JdbcQueryTaskParameters) obj;

		// 基本信息不匹配就直接返回，不再判断参数，以便提高效率
		if (!isBaseInfoEquals(parameters)) {
			return false;
		}

		return isArgumentEquals(parameters);
	}

	private boolean isBaseInfoEquals(JdbcQueryTaskParameters parameters) {
		boolean equals = (sql.equals(parameters.getSql()) && fetchSize == parameters.getFetchSize() && returnKeys == parameters
				.isReturnKeys());
		return equals;
	}

	private boolean isArgumentEquals(JdbcQueryTaskParameters parameters) {
		Object[] paramArgs = parameters.getArgs();
		if (args == null && paramArgs == null) {
			return true;
		}

		int currentLen = ArrayUtils.getArrayOrListLength(args);
		int paramLen = ArrayUtils.getArrayOrListLength(paramArgs);

		if (currentLen != paramLen) {
			return false;
		}

		return isArgumentElementEquals(paramArgs, currentLen);

	}

	private boolean isArgumentElementEquals(Object[] paramArgs, int currentLen) {
		for (int i = 0; i < currentLen; i++) {
			Object arg = args[i];
			Object paramArg = paramArgs[i];
			if ((arg == null && paramArg == null) || (arg != null && arg.equals(paramArg))) {
				continue;
			}

			return false;
		}
		
		return true;
	}

	@Override
	public int hashCode() {
		return this.hashCode;
	}

	public String getSql() {
		return sql;
	}

	public int getFetchSize() {
		return fetchSize;
	}

	public boolean isReturnKeys() {
		return returnKeys;
	}

	public PreparedStatementCallback<?> getAction() {
		return action;
	}

	public Object[] getArgs() {
		return args;
	}

}
